package org.sean.framework.code;

import org.sean.framework.enums.EnumValue;
import org.sean.framework.util.I18nUtil;
import org.sean.framework.util.StringUtil;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;

/**
 * 状态码
 *
 * @author xielei
 */
@SuppressWarnings("unused")
public final class StatusInfo implements Serializable {
    static final long serialVersionUID = -7034453190545766939L;

    private static final Map<String, String> COMMON_MESSAGES = new HashMap<>();
    private static final String BASE_NAME = "values/status_strings";

    static {
        ResourceBundle bundle = ResourceBundle.getBundle("values/common_status_strings");
        Enumeration<String> keys = bundle.getKeys();
        String key;
        while (keys.hasMoreElements()) {
            key = keys.nextElement();
            COMMON_MESSAGES.put(key, bundle.getString(key));
        }
    }

    /**
     * 状态码
     */
    private int code;
    /**
     * 状态级别
     */
    private Level level;
    /**
     * 消息Key
     */
    private transient String msgKey;
    /**
     * 消息参数
     */
    private transient Object[] msgArgs;

    /**
     * 异常信息
     */
    private Exception exception;

    /**
     * @param code 状态码
     */
    public StatusInfo(int code) {
        this(code, null, null);
    }


    /**
     * @param code   状态码
     * @param msgKey 消息文案
     */
    public StatusInfo(int code, String msgKey) {
        this(code, msgKey, null, null);
    }


    /**
     * @param code    状态码
     * @param msgKey  消息文案
     * @param msgArgs 文案参数
     */
    public StatusInfo(int code, String msgKey, Object[] msgArgs) {
        this(code, msgKey, msgArgs, null);
    }

    /**
     * @param code    状态码
     * @param msgKey  消息文案
     * @param msgArgs 文案参数
     * @param level   状态级别
     */
    public StatusInfo(int code, String msgKey, Object[] msgArgs, Level level) {
        this.code = code;
        this.msgKey = msgKey;
        if (msgArgs != null) {
            this.msgArgs = Arrays.copyOf(msgArgs, msgArgs.length);
        }
        this.level = level;
    }

    /**
     * @return 初始化异常
     */
    public static StatusInfo serverInitError() {
        return new StatusInfo(StatusCode.ERROR_SERVER_STARTING, "common_status_server_start_error");
    }

    /**
     * @return 未知错误
     */
    public static StatusInfo unknownError() {
        return new StatusInfo(StatusCode.ERROR_UNKNOW, "common_status_unkonw");
    }

    /**
     * @return 成功
     */
    public static StatusInfo success() {
        return new StatusInfo(StatusCode.SUCCESS, "common_status_success");
    }

    /**
     * @return 内存异常
     */
    public static StatusInfo outOfMemoryError() {
        return new StatusInfo(StatusCode.ERROR_MEMORY, "common_status_out_of_memory");
    }

    /**
     * @return 未登录
     */
    public static StatusInfo notLoginError() {
        return new StatusInfo(StatusCode.ERROR_NOT_LOGINED, "common_status_not_login");
    }

    /**
     * @return 登录已过期
     */
    public static StatusInfo loginTimeoutError() {
        return new StatusInfo(StatusCode.ERROR_LOGIN_TIMEOUT, "common_status_login_timeout");
    }

    /**
     * @return 数据异常
     */
    public static StatusInfo dataInvalidError() {
        return new StatusInfo(StatusCode.ERROR_DATA_INVALID, "common_status_data_invalid");
    }

    /**
     * @return 验证失败
     */
    public static StatusInfo authorityFailed() {
        return new StatusInfo(StatusCode.ERROR_AUTHORITY_FAILED, "common_status_authority_failed");
    }

    /**
     * @return 操作不支持
     */
    public static StatusInfo notSupported() {
        return new StatusInfo(StatusCode.ERROR_NOT_SUPPORTED, "common_status_opt_not_supported");
    }

    /**
     * @return 编码错误
     */
    public static StatusInfo encoderError() {
        return new StatusInfo(StatusCode.ERROR_ENCODER, "common_status_encoder");
    }

    /**
     * @return 解码错误
     */
    public static StatusInfo decoderError() {
        return new StatusInfo(StatusCode.ERROR_DECODER, "common_status_decoder");
    }

    /**
     * @return 数据校验失败
     */
    public static StatusInfo verifyFailed() {
        return new StatusInfo(StatusCode.ERROR_VERIFY_FAILED, "common_status_verify_failed");
    }

    /**
     * @return 操作超时
     */
    public static StatusInfo operationTimeoutError() {
        return new StatusInfo(StatusCode.ERROR_TIMEOUT, "common_status_opt_timeout");
    }

    /**
     * @return 参数错误
     */
    public static StatusInfo paramsInvalidError() {
        return new StatusInfo(StatusCode.ERROR_PARAMS, "common_status_params_invalid");
    }

    /**
     * @return 数据不存在
     */
    public static StatusInfo dataNotExistError() {
        return new StatusInfo(StatusCode.ERROR_NOT_EXIST, "common_status_data_not_exist");
    }

    /**
     * @return 数据已存在
     */
    public static StatusInfo dataExistError() {
        return new StatusInfo(StatusCode.ERROR_EXIST, "common_status_data_exist");
    }

    /**
     * @return 参数不是JSON格式
     */
    public static StatusInfo paramsNotJsonError() {
        return new StatusInfo(StatusCode.ERROR_PARAMS_NOT_JSON, "common_status_params_not_json");
    }

    /**
     * @return 数据访问失败
     */
    public static StatusInfo dataAccessFailed() {
        return new StatusInfo(StatusCode.ERROR_DATA_ACCESS, "common_status_data_access_failed");
    }

    /**
     * @return 数据库访问失败
     */
    public static StatusInfo databaseAccessFailed() {
        return new StatusInfo(StatusCode.ERROR_DATABASE, "common_status_database_access_failed");
    }

    /**
     * @return Redis访问失败
     */
    public static StatusInfo redisAccessFailed() {
        return new StatusInfo(StatusCode.ERROR_REDIS, "common_status_redis_access_failed");
    }

    /**
     * @return 网络异常
     */
    public static StatusInfo netError() {
        return new StatusInfo(StatusCode.ERROR_NET, "common_status_net_error");
    }

    /**
     * @return Kafka访问异常
     */
    public static StatusInfo kafkaAccessFailed() {
        return new StatusInfo(StatusCode.ERROR_KAFKA, "common_status_kafka_access_failed");
    }

    /**
     * @return 签名错误
     */
    public static StatusInfo signInvalidError() {
        return new StatusInfo(StatusCode.ERROR_SIGN, "common_status_sign_invalid");
    }

    /**
     * @return Header校验失败
     */
    public static StatusInfo headerInvalidError() {
        return new StatusInfo(StatusCode.ERROR_HEADER, "common_status_header_invalid");
    }

    /**
     * @return 同步方法错误
     */
    public static StatusInfo syncError() {
        return new StatusInfo(StatusCode.ERROR_SYNC, "common_status_sync_error");
    }

    /**
     * @return 同步方法超时错误
     */
    public static StatusInfo syncTimeoutError() {
        return new StatusInfo(StatusCode.ERROR_SYNC_TIMEOUT, "common_status_sync_timeout");
    }

    /**
     * @return 定时任务执行失败
     */
    public static StatusInfo scheduleTaskError() {
        return new StatusInfo(StatusCode.ERROR_SCHEDULE_TASK, "schedule_status_error");
    }

    /**
     * @return 操作取消
     */
    public static StatusInfo operationCancel() {
        return new StatusInfo(StatusCode.ERROR_CANCEL, "common_status_opt_cancel");
    }

    /**
     * @return 服务调用失败
     */
    public static StatusInfo accessMsError() {
        return new StatusInfo(StatusCode.ERROR_ACCESS_MS, "common_status_access_ms");
    }

    /**
     * @return 融云访问失败
     */
    public static StatusInfo imError() {
        return new StatusInfo(StatusCode.ERROR_RONG_CLOUD, "common_status_rongcloud_error");
    }

    /**
     * @return 短信通道访问失败
     */
    public static StatusInfo smsError() {
        return new StatusInfo(StatusCode.ERROR_SMS, "common_status_sms_error");
    }

    /**
     * @return 邮件通道访问失败
     */
    public static StatusInfo emailError() {
        return new StatusInfo(StatusCode.ERROR_EMAIL, "common_status_email_error");
    }

    /**
     * @return OSS访问失败
     */
    public static StatusInfo ossError() {
        return new StatusInfo(StatusCode.ERROR_OSS_ALIYUN, "common_status_oss_aliyun");
    }

    public StatusInfo setAnyMessage(String msg) {
        this.msgKey = "common_status_any";
        this.msgArgs = new String[]{msg};
        return this;
    }

    /**
     * 设置消息文案
     *
     * @param msgKey  国际化文案Key
     * @param msgArgs 文案参数
     * @return 状态信息
     */
    public StatusInfo setMessage(String msgKey, Object... msgArgs) {
        this.msgKey = msgKey;
        this.msgArgs = msgArgs;
        return this;
    }

    /**
     * @return 消息文案
     */
    public String getMessage() {
        if (StringUtil.isEmpty(msgKey)) {
            return "";
        }
        if (COMMON_MESSAGES.containsKey(msgKey)) {
            return StringUtil.formatContent(COMMON_MESSAGES.get(msgKey), msgArgs);
        }
        return I18nUtil.getLocalResource(Locale.getDefault(), BASE_NAME, msgKey, msgArgs);
    }

    /**
     * 设置消息文案
     *
     * @param msgKey 国际化文案Key
     * @return 状态信息
     */
    public StatusInfo setMessage(String msgKey) {
        this.msgKey = msgKey;
        return this;
    }

    /**
     * @return 获取消息key
     */
    public String getMsgKey() {
        return this.msgKey;
    }

    /**
     * @return 级别
     */
    public Integer getLevel() {
        if (level != null) {
            return level.getValue();
        }
        return null;
    }

    /**
     * 设置状态级别
     *
     * @param level 级别
     * @return 状态信息
     */
    public StatusInfo setLevel(Level level) {
        this.level = level;
        return this;
    }

    /**
     * @return 状态码
     */
    public int getCode() {
        return code;
    }

    /**
     * @param code 设置状态码
     * @return 状态信息
     */
    public StatusInfo setCode(int code) {
        this.code = code;
        return this;
    }

    /**
     * @return Exception
     */
    public Exception getException() {
        return exception;
    }

    /**
     * 状态级别
     */
    public enum Level implements EnumValue<Integer> {
        /**
         * 无
         */
        NONE(null),
        /**
         * 错误
         */
        ERROR(0),
        /**
         * 警告
         */
        WARNING(1),
        /**
         * 提示
         */
        INFO(2);

        private Integer value;

        Level(Integer value) {
            this.value = value;
        }

        @Override
        public Integer getValue() {
            return value;
        }
    }

}
